#####################################################################
#  Map.py
#  KnowledgeEngine
#  
#  Created by John Meredith on 2007-01-24.
#  Copyright 2007 Faulkner Technologies. All rights reserved.
#####################################################################

#####################################################################
## Knowledge Engine Library Imports
from Products.KnowledgeEngine.Common import *
from Products.KnowledgeEngine.Core import *
from Products.KnowledgeEngine.Component import Component, ComponentInfo
from Products.KnowledgeEngine.Assessible import Assessible
from Products.KnowledgeEngine.AssessmentComponentState import AssessmentComponentState
from Products.KnowledgeEngine.AssessmentComponentValueTypes import *
from Products.KnowledgeEngine.Exportable import Exportable
from Products.KnowledgeEngine.KERLExtensions import KERLExtensions
from Products.KnowledgeEngine.PropertyDefinition import *
from Products.KnowledgeEngine.PropertyTypes import *
from Products.KnowledgeEngine.PropertyFormats import *
from Products.KnowledgeEngine.PropertyStructures import *
from Products.KnowledgeEngine.KERFProcessor import *
from Products.KnowledgeEngine.KERLProcessor import InvalidKerlOperator


#####################################################################
## Zope Library Imports
from Globals import DTMLFile
from App.ImageFile import ImageFile


#####################################################################
## Python Library Imports
# (none)


FAULKNER_OFFICES = '-27.467193219240155:153.0463743209839:4';

#####################################################################
## MapInfo Class Definition
class MapInfo(ComponentInfo):
    """
        Defines the class info methods, defining information about
        the class without needing an instance of the class
    """

    #---------------------------------------------------------------#
    def getClassName(self):
        """
            Returns the classname
        """
        
        return "Map"

    
    #---------------------------------------------------------------#
    def getDisplayName(self):
        """
            Return a friendly name for the class instances (this is
            used for displaying in lists etc)
        """

        return "Map"

    
    #---------------------------------------------------------------#
    def getIdentityType(self):
        """
            Returns the identity type
        """
        
        return self.getDisplayName().lower()


    #---------------------------------------------------------------#
    def getIcon(self):
        """
            Return the appropriate icon file for the class
        """
        
        return 'Map_icon.png'


    #---------------------------------------------------------------#
    def getClassIcon(self):
        """
            Return the appropriate icon file for the class
        """
        
        return ImageFile('skins/Map_icon.png', globals())

    
    #---------------------------------------------------------------#
    def isInstanceOf(self, className):
        """
            Returns if the class is an instance of the specified
            className, or implements the interface specified 
            by the className
        """

        return className in ('Assessible', ) or ComponentInfo.isInstanceOf(self, className)

    
    #---------------------------------------------------------------#
    def onConfigureProperties(self):
        """
            Automatically called by the Knowledge Engine once
            the class has been loaded.  Use this method to register 
            class specific properties using the PropertyReflection interface.
            
            If this class is sub-classed, a call must be made to
            the super-class to ensure super-class properties are
            correctly registered
            
            NOTE: This method is called before ClassInfo.onAfterStartup()            
        """

        #initialise the super-class properties for reflection
        ComponentInfo.onConfigureProperties(self)

        self.addPropertyDefinition(PropertyDefinition(
            identity='googleMapsAPIKey',
            displayName="Google Maps API Key",
            description="A Google Maps API key is required to enable use of Google Maps",
            defaultValue="",
            propertyType=pt_STRING,
            propertyFormat=pf_TEXT_SINGLELINE,
            propertyStructure=ps_ATOMIC,
            isMandatory=true,
        ))

        self.addPropertyDefinition(PropertyDefinition(
            identity='defaultLocation',
            displayName="Default Location",
            description="Default location the map will center on in the form of \"latitude, longitude, zoom level\"",
            defaultValue=FAULKNER_OFFICES, # <-- Map of Australia
            propertyType=pt_STRING,
            propertyFormat=pf_TEXT_SINGLELINE,
            propertyStructure=ps_ATOMIC,
        ))

    #---------------------------------------------------------------#


#####################################################################
## Map Class Definition
class Map(Component, Assessible, KERLExtensions, Exportable):
    """
        Defines a component to visually display webbase mapping
        services in an assessment.
        
        NOTE: This component is extreme ALPHA and has been written
        as a demonstration ONLY. Not for use in production. May harm
        you and/or your children if ingested or inhaled.
    """
    
    #---------------------------------------------------------------#
    #TRANSIENT: a ClassInfo implementation instance to provide info about this class
    _CLASSINFO = MapInfo()

    
    #---------------------------------------------------------------#
    def __init__(self, id, identity):
        """
            Constructor for the Map
        """

        Component.__init__(self, id, identity)

    
    #---------------------------------------------------------------#
    def onAfterInstanciation(self):
        """
            Handle Knowledge Engine specific actions after this object 
            has been loaded into memory.  
            
            This is useful for performing backwards compatibility
        """
        
        #perform Component.onAfterInstanciation processing
        Component.onAfterInstanciation(self)

    
    #---------------------------------------------------------------#
    def onAfterIdentityChange(self, identityMappings):
        """
            Handle Knowledge Engine specific actions after the 
            identity of this object has changed.
            
            The identityMappings dictionary holds 
            mappings from oldIdentities -> newIdentities
            (including this object)
                        
        """

        #perform default identity changes
        Component.onAfterIdentityChange(self, identityMappings)


    #---------------------------------------------------------------#
    def hasReportContent(self):
        """
            This is a *hack* to overcome a new addition (r922) which
            will only display a component in the report if it has
            report content.
        """

        return True

    
    #---------------------------------------------------------------#
    # BEGIN: Generic Maps Implementation                            #
    #---------------------------------------------------------------#
    def getDefaultLocation(self):
        """
            Returns the default location given as a comma-separated
            string consisting of latitude and longitude
        """
        
        return getattr(self, "defaultLocation", FAULKNER_OFFICES)
    #---------------------------------------------------------------#
    # END: Genric Maps Implementation                               #
    #---------------------------------------------------------------#


    #---------------------------------------------------------------#
    # BEGIN: Google Maps Implementation                             #
    #---------------------------------------------------------------#
    def getGoogleMapsAPIKey(self):
        """
            Returns the Google API key
        """
        
        return getattr(self, 'googleMapsAPIKey', '')


    #---------------------------------------------------------------#
    def getGoogleMapsJavascriptSource(self):
        """
            Returns the Google Javascript source string
            
            NOTE: Had to do it this was as I couldn't find an easy
            way of stopping tal:attributes from escaping the ampersand
        """
        
        return "<script type=\"text/javascript\" src=\"http://maps.google.com/maps?file=api&v=2&key=%s\"></script>" % self.getGoogleMapsAPIKey()
    #---------------------------------------------------------------#
    # END: Google Maps Implementation                               #
    #---------------------------------------------------------------#


    #---------------------------------------------------------------#
    # BEGIN: Assessible Implementation                              #
    #---------------------------------------------------------------#
    def getAssessmentValueType(self):
        """
            ABSTRACT: Returns the type of the value that is to be stored
            for this component when it's assessment state is persisted.
            
            NOTE 1: See AssessmentComponentValueTypes for a list of defined contants       
            NOTE 2: This method MUST be overriden in the implementing
            class to specify the correct type for value persistence
            
            RETURN TYPE: String
        """
        
        #multiplechoice assessment values are strings
        return st_STRING
        
    #---------------------------------------------------------------#
        
    def getDefaultAssessmentState(self, assessment):
        """
            ABSTRACT: Constructs and returns a suitable 'default' 
            AssessmentComponentState for the provided Assessment
            instance.

            NOTE: This method MUST be overriden in the implementing
            class to provide a suitable default value for the component
            
            RETURN TYPE: AssessmentComponentState
        """
        
        return AssessmentComponentState(
            assessment.getIdentity(),
            assessment.getModelIdentity(),
            self.getIdentity(),
            self.getAssessmentValueType(),
            FAULKNER_OFFICES,
            revision=assessment.getRevision()
        )
            
    #---------------------------------------------------------------#

    def updateAssessmentState(self, assessment, formValue):
        """
            ABSTRACT: Updates the specified assessment using
            the provided HTTP REQUEST formValue.
            
            NOTE: This method MUST be overriden in the implementing
            class to suitably update the component state
        """
        
        print "Map.updateAssessmentState formValue: %s" % (formValue, )

        Component.updateAssessmentState( self, assessment, formValue )
        
        #get the current assessment state for the component from the assessment
        state = assessment.getComponentState(self.getIdentity())
        
        #update the current state
        state.setValue(formValue)
        
        #update the assessment
        assessment.setIsModified(true)
    #---------------------------------------------------------------#
    # END: Assessible Implementation                                #
    #---------------------------------------------------------------#
    

#####################################################################
# Register Component Information with the Knowledge Engine
registerGenericObjectClass(Map)
